#pragma once

#include <AVUIDispatcherObject.h>
#include <AVUIIHaveResources.h>
#include <AVUINameScope.h>
#include <AVUIStyleStructures.h>
#include <AVUIFrugalMap.h>

namespace AVUI {

class FrameworkElementFactory;
class HybridDictionary;
class ProvideValueServiceProvider;
class EventHandlersStore;
class OptimizedTemplateContent;
typedef TArray< TRefCountedPtr<HybridDictionary> > HybridDictionaryArray;
typedef ItemStructList< TRefCountedPtr<DependencyObject> > DependencyObjectList;

/// <summary>Enables the instantiation of a tree of <see cref="T:System.Windows.FrameworkElement" /> and/or <see cref="T:System.Windows.FrameworkContentElement" /> objects.</summary>
class FrameworkTemplate : public DispatcherObject, public IHaveResources, public INameScope
{
public:
    DECLARE_ELEMENT(FrameworkTemplate, DispatcherObject);

#pragma region Public Methods

    /// <summary>Finds the element associated with the specified name defined within this template.</summary>
    /// <returns>The element associated with the specified name.</returns>
    /// <param name="name">The string name.</param>
    /// <param name="templatedParent">The context of the <see cref="T:System.Windows.FrameworkElement" /> where this template is applied.</param>
    Object* FindName(String* pName, FrameworkElement* pTemplatedParent);

    /// <summary>Loads the content of the template as an instance of an object and returns the root element of the content.</summary>
    /// <returns>The root element of the content. Calling this multiple times returns separate instances.</returns>
    TRefCountedPtr<DependencyObject> LoadContent();

    /// <summary>Registers a new name/object pair into the current name scope.</summary>
    /// <returns />
    /// <param name="name">The name to register.</param>
    /// <param name="scopedElement">The object to be mapped to the provided name.</param>
    void RegisterName(String* pName, Object* pScopedElement) { VerifyAccess(); m_pNameScope->RegisterName(pName,pScopedElement); }

    /// <summary>Locks the template so it cannot be changed.</summary>
    void Seal();

    /// <summary>Removes a name/object mapping from the name scope.</summary>
    /// <returns />
    /// <param name="name">The name of the mapping to remove.</param>
    void UnregisterName(String* pName) { VerifyAccess(); m_pNameScope->UnregisterName(pName); }

#pragma endregion Public Methods
 
#pragma region Public Properties
 
    /// <summary>Gets a value that indicates whether this template has optimized content.</summary>
    /// <returns>true if this template has optimized content; otherwise, false.</returns>
    bool get_HasContent();

    /// <summary>Gets a value that indicates whether this object is in an immutable state so it cannot be changed.</summary>
    /// <returns>true if this object is in an immutable state; otherwise, false.</returns>
    bool get_IsSealed() { VerifyAccess(); return m_sealed; }

    /// <summary>Gets or sets the collection of resources that can be used within the scope of this template.</summary>
    /// <returns>The resources that can be used within the scope of this template.</returns>
    ResourceDictionary* get_Resources();
    void set_Resources(ResourceDictionary* pResources);
    IMPLEMENT_REFERENCE_PROPERTY(Resources, ResourceDictionary, false);

    /// <summary>Gets or sets the root node of the template.</summary>
    /// <returns>The root node of the template.</returns>
    FrameworkElementFactory* get_VisualTree() { VerifyAccess(); return m_pTemplateRoot; }
    void set_VisualTree(FrameworkElementFactory* pVisualTree);
    IMPLEMENT_REFERENCE_PROPERTY(VisualTree, FrameworkElementFactory, false);
    
#pragma endregion Public Properties

#pragma region INameScope support

    /// <summary>This member supports the Windows Presentation Foundation (WPF) infrastructure and is not intended to be used directly from your code.</summary>
    /// <returns />
    /// <param name="name" />
    virtual Object* FindName(String* pName) AVUI_OVERRIDE { VerifyAccess(); return m_pNameScope->FindName(pName); }    

    /// <summary>WPFG deviation -- return underlying object.</summary>
    virtual Object* get_Object() AVUI_OVERRIDE { return this; }

#pragma endregion INameScope support


protected:

#pragma region Protected Methods

    /// <summary>Initializes a new instance of the <see cref="T:System.Windows.FrameworkTemplate" /> class. </summary>
    FrameworkTemplate();

    /// <summary>When overridden in a derived class, supplies rules for the element this template is applied to.</summary>
    /// <returns />
    /// <param name="templatedParent">The element this template is applied to.</param>
    virtual void ValidateTemplatedParent(FrameworkElement* pTemplatedParent) { };
 

#pragma endregion Protected Methods

public:

#pragma region Internal Methods

    bool ApplyTemplateContent(UncommonField<HybridDictionaryArray>* pTemplateDataField, FrameworkElement* pContainer);
    virtual bool BuildVisualTree(FrameworkElement* pContainer) { return false; }
    void CheckSealed();
    Object* FindResource(Object* pResourceKey, bool allowDeferredResourceReference, bool mustReturnDeferredResourceReference);
    TRefCountedPtr<DependencyObject> LoadContent(DependencyObject* pContainer, DependencyObjectList* pAffectedChildren, UncommonField<HybridDictionary>* pTemplatedNonFeChildrenField);
    virtual void ProcessTemplateBeforeSeal() { }
    void SetResourceReferenceState();
    virtual void SetTargetTypeInternal(const Type* pTargetType) = 0;
    static void SetTemplateParentValues(String* pName, Object* pElement, FrameworkTemplate* pFrameworkTemplate, TRefCountedPtr<ProvideValueServiceProvider>* ppProvideValueServiceProvider);

#pragma endregion Internal Methods

#pragma region Internal Properties

    bool get_CanBuildVisualTree() { return ReadInternalFlag(InternalFlags::CanBuildVisualTree); }
    void set_CanBuildVisualTree(bool value) { WriteInternalFlag(InternalFlags::CanBuildVisualTree, value); }

    virtual TRefCountedPtr<Object> get_DataTypeInternal() { return NULL; }
    EventHandlersStore* get_EventHandlersStore() { return m_pEventHandlersStore; }
    bool get_HasChildResourceReferences() { return ReadInternalFlag(InternalFlags::HasChildResourceReferences); }
    bool get_HasContainerResourceReferences() { return ReadInternalFlag(InternalFlags::HasContainerResourceReferences); }
    bool get_HasEventDependents() { return EventDependents.get_Count() > 0; }
    bool get_HasInstanceValues() { return m_hasInstanceValues; }

    bool get_HasLoadedChangeHandler() { return ReadInternalFlag(InternalFlags::HasLoadedChangeHandler); }
    void set_HasLoadedChangeHandler(bool value) { WriteInternalFlag(InternalFlags::HasLoadedChangeHandler, value); }

    bool get_HasResourceReferences() { return ResourceDependents.get_Count() > 0; }

    OptimizedTemplateContent* get_OptimizedTemplateContent();

    virtual const Type* get_TargetTypeInternal() { return NULL; }
    virtual TriggerCollection* get_TriggersInternal() { return NULL; }

#pragma endregion Internal Properties

#pragma region Internal Fields

    TRefCountedPtr<HybridDictionary> m_pChildIndexFromChildName;
    TRefCountedPtr<HybridDictionary> m_pDataTriggerRecordFromBinding;
    int m_lastChildIndex;
    TRefCountedPtr<OptimizedTemplateContent> m_pOptimizedTemplateContent;
    TRefCountedPtr<ResourceDictionary> m_pResources;
    TRefCountedPtr<HybridDictionary> m_TemplateChildLoadedDictionary;
    TRefCountedPtr<HybridDictionary> m_pTriggerActions;
    ItemStructList<ChildRecord> ChildRecordFromChildIndex;
    ItemStructList<ContainerDependent> ContainerDependents;
    TRefCountedPtr<HybridDictionary> DataTriggersWithActions;
    TRefCountedPtr<HybridDictionary> DeferredActions;
    ItemStructList<ChildEventDependent> EventDependents;
    FrugalMap PropertyTriggersWithActions;
    ItemStructList<ChildPropertyDependent> ResourceDependents;
    ItemStructList< ItemStructMap<TriggerSourceRecord> > TriggerSourceRecordFromChildIndex;

#pragma endregion Internal Fields

#pragma region Internal Flags

    class InternalFlags
    {
    public:
        enum Enum
        {
            CanBuildVisualTree = 4,
            HasChildResourceReferences = 0x20,
            HasContainerResourceReferences = 0x10,
            HasLoadedChangeHandler = 8
        };
    };

#pragma endregion Internal Flags

#pragma region Internal TemplateChildLoadedFlags

    class TemplateChildLoadedFlags : public Object
    {
    public:
        DECLARE_ELEMENT(TemplateChildLoadedFlags, DispatcherObject);
    
        TemplateChildLoadedFlags() : HasLoadedChangedHandler(false), HasUnloadedChangedHandler(false) { }
    
        bool HasLoadedChangedHandler;
        bool HasUnloadedChangedHandler;
    };
    
#pragma endregion Internal TemplateChildLoadedFlags

private:

#pragma region Private Methods

    bool ReadInternalFlag(InternalFlags::Enum reqFlag);
    void ValidateVisualTree(FrameworkElementFactory* pTemplateRoot);
    void WriteInternalFlag(InternalFlags::Enum reqFlag, bool set);

#pragma endregion Private Methods
 
#pragma region Private Field

    TRefCountedPtr<EventHandlersStore> m_pEventHandlersStore;
    unsigned int m_flags;
    bool m_hasInstanceValues;
    TRefCountedPtr<NameScope> m_pNameScope;
    bool m_sealed;
    TRefCountedPtr<FrameworkElementFactory> m_pTemplateRoot;

#pragma endregion Private Fields

};

}; // namespace AVUI




